package rexsee.network;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.lang.RexseeLanguage;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.webkit.CookieManager;

public class RexseeNetwork implements JavascriptInterface {

	public static final String INTERFACE_NAME = "Network";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeNetwork(childBrowser);
	}

	public static final String EVENT_ONPINGRETURNED = "onPingReturned";

	public abstract class PingRunnable {
		public abstract void run(String url, int responseCode, long milliseconds);
	}

	private final Context mContext;
	private final Browser mBrowser;

	public RexseeNetwork(Context context) {
		super();
		mBrowser = null;
		mContext = context;
	}
	public RexseeNetwork(Browser browser) {
		super();
		mBrowser = browser;
		mContext = browser.getContext();
		browser.eventList.add(EVENT_ONPINGRETURNED);
	}

	public static InetAddress getInetAddress() {
		ArrayList<InetAddress> addresses = getInetAddresses();
		if (addresses == null || addresses.size() == 0) return null;
		InetAddress rtn = null;
		for (int i = 0; i < addresses.size(); i++) {
			InetAddress addr = addresses.get(i);
			if (addr.isLoopbackAddress()) continue;
			String ip = addr.getHostAddress();
			if (ip == null || ip.length() == 0) continue;
			if (ip.contains("::")) continue; //IPv6
			if (ip.split("\\.").length != 4) continue;
			rtn = addr;
			break;
		}
		return rtn;
		/*
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress()) return inetAddress;
				}
			}
			return null;
		} catch (Exception e) {
			return null;
		}
		*/
	}
	public static ArrayList<InetAddress> getInetAddresses() {
		try {
			ArrayList<InetAddress> addrs = new ArrayList<InetAddress>();
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					addrs.add(enumIpAddr.nextElement());
				}
			}
			return addrs;
		} catch (Exception e) {
			return null;
		}
	}
	public void ping(final String url, final int pingTimeout, final PingRunnable runnable) {
		final String pingUrl = mBrowser.urlListeners.getAbsoluteUrl(url);
		String scheme = Uri.parse(pingUrl).getScheme();
		if (!scheme.equals("http") && !scheme.equals("https")) {
			mBrowser.exception(getInterfaceName(), "Wrong Scheme!");
			return;
		}
		if (!mBrowser.domainWhiteList.isValidUrl(pingUrl)) {
			mBrowser.exception(getInterfaceName(), "Url not allowed.");
			return;
		}
		new Thread() {
			@Override
			public void run() {
				if (mBrowser != null) mBrowser.progressDialog.show(RexseeLanguage.PROGRESS_ONGOING);
				try {
					long start = System.currentTimeMillis();
					URL url = new URL(pingUrl);
					HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
					CookieManager cookieManager = CookieManager.getInstance();
					String cookie = cookieManager.getCookie(pingUrl);
					if (cookie != null) {
						urlc.setRequestProperty("Cookie", cookie);
						//After urlConnection.connect(); could retrieve sessionId with urlConnection.getHeaderField("Set-Cookie");
					}
					urlc.setRequestProperty("User-Agent", mBrowser.getSettings().getUserAgentString());
					urlc.setRequestProperty("Connection", "close");
					urlc.setConnectTimeout(1000 * pingTimeout);
					urlc.connect();
					if (mBrowser != null) mBrowser.progressDialog.hide();
					runnable.run(pingUrl, urlc.getResponseCode(), System.currentTimeMillis() - start);
				} catch (IOException e) {
					if (mBrowser != null) mBrowser.progressDialog.hide();
					runnable.run(pingUrl, -1, -1);
				}
			}
		}.start();
	}

	//JavaScript Interface
	public boolean isReady() {
		ConnectivityManager conn = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo netinfo = conn.getActiveNetworkInfo();
		return (netinfo == null || !netinfo.isAvailable()) ? false : true;
	}
	public void ping(final String pingUrl, final int pingTimeout) {
		ping(pingUrl, pingTimeout, new PingRunnable() {
			@Override
			public void run(String pingUrl, int responseCode, long milliseconds) {
				mBrowser.eventList.run(EVENT_ONPINGRETURNED, new String[]{pingUrl, String.valueOf(responseCode), String.valueOf(milliseconds)});
			}
		});
	}

	//Local information
	public String getDisplayNames() {
		String rtn = "";
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				if (rtn != "") rtn += ",";
				rtn += "\"" + en.nextElement().getDisplayName() + "\"";
			}
			return "[" + rtn + "]";
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "[]";
		}
	}
	public String getIpAddress() {
		InetAddress addr = getInetAddress();
		return (addr == null) ? "" : addr.getHostAddress();
	}
	public String getHostName() {
		InetAddress addr = getInetAddress();
		return (addr == null) ? "" : addr.getHostName();
	}
	public String getIpAddresses() {
		ArrayList<InetAddress> list = getInetAddresses();
		String rtn = "";
		for (int i = 0; i < list.size(); i++) {
			if (i > 0) rtn += ",";
			rtn += "\"" + list.get(i).getHostAddress() + "\"";
		}
		return "[" + rtn + "]";
	}
	public String getHostNames() {
		ArrayList<InetAddress> list = getInetAddresses();
		String rtn = "";
		for (int i = 0; i < list.size(); i++) {
			if (i > 0) rtn += ",";
			rtn += "\"" + list.get(i).getHostName() + "\"";
		}
		return "[" + rtn + "]";
	}

	//Remote information
	public String getHostName(String host) {
		try {
			InetAddress address = InetAddress.getByName(host);
			return (address == null) ? "" : address.getHostName();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "";
		}
	}
	public String getIpAddress(String host) {
		try {
			InetAddress address = InetAddress.getByName(host);
			return (address == null) ? "" : address.getHostAddress();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "";
		}
	}
	public String getLocalHostIpAddress() {
		try {
			InetAddress address = InetAddress.getLocalHost();
			return (address == null) ? "" : address.getHostAddress();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "";
		}
	}

}
